home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / p_view.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  28.1 KB  |  1,130 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. #include "g_local.h"
  22. #include "m_player.h"
  23.  
  24.  
  25.  
  26. static    edict_t        *current_player;
  27. static    gclient_t    *current_client;
  28.  
  29. static    vec3_t    forward, right, up;
  30. float    xyspeed;
  31.  
  32. float    bobmove;
  33. int        bobcycle;        // odd cycles are right foot going forward
  34. float    bobfracsin;        // sin(bobfrac*M_PI)
  35.  
  36. /*
  37. ===============
  38. SV_CalcRoll
  39.  
  40. ===============
  41. */
  42. float SV_CalcRoll (vec3_t angles, vec3_t velocity)
  43. {
  44.     float    sign;
  45.     float    side;
  46.     float    value;
  47.     
  48.     side = DotProduct (velocity, right);
  49.     sign = side < 0 ? -1 : 1;
  50.     side = fabs(side);
  51.     
  52.     value = sv_rollangle->value;
  53.  
  54.     if (side < sv_rollspeed->value)
  55.         side = side * value / sv_rollspeed->value;
  56.     else
  57.         side = value;
  58.     
  59.     return side*sign;
  60.     
  61. }
  62.  
  63.  
  64. /*
  65. ===============
  66. P_DamageFeedback
  67.  
  68. Handles color blends and view kicks
  69. ===============
  70. */
  71. void P_DamageFeedback (edict_t *player)
  72. {
  73.     gclient_t    *client;
  74.     float    side;
  75.     float    realcount, count, kick;
  76.     vec3_t    v;
  77.     int        r, l;
  78.     static    vec3_t    power_color = {0.0, 1.0, 0.0};
  79.     static    vec3_t    acolor = {1.0, 1.0, 1.0};
  80.     static    vec3_t    bcolor = {1.0, 0.0, 0.0};
  81.  
  82.     client = player->client;
  83.  
  84.     // flash the backgrounds behind the status numbers
  85.     client->ps.stats[STAT_FLASHES] = 0;
  86.     if (client->damage_blood)
  87.         client->ps.stats[STAT_FLASHES] |= 1;
  88.     if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
  89.         client->ps.stats[STAT_FLASHES] |= 2;
  90.  
  91.     // total points of damage shot at the player this frame
  92.     count = (client->damage_blood + client->damage_armor + client->damage_parmor);
  93.     if (count == 0)
  94.         return;        // didn't take any damage
  95.  
  96.     // start a pain animation if still in the player model
  97.     if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
  98.     {
  99.         static int        i;
  100.  
  101.         client->anim_priority = ANIM_PAIN;
  102.         if (client->ps.pmove.pm_flags & PMF_DUCKED)
  103.         {
  104.             player->s.frame = FRAME_crpain1-1;
  105.             client->anim_end = FRAME_crpain4;
  106.         }
  107.         else
  108.         {
  109.             i = (i+1)%3;
  110.             switch (i)
  111.             {
  112.             case 0:
  113.                 player->s.frame = FRAME_pain101-1;
  114.                 client->anim_end = FRAME_pain104;
  115.                 break;
  116.             case 1:
  117.                 player->s.frame = FRAME_pain201-1;
  118.                 client->anim_end = FRAME_pain204;
  119.                 break;
  120.             case 2:
  121.                 player->s.frame = FRAME_pain301-1;
  122.                 client->anim_end = FRAME_pain304;
  123.                 break;
  124.             }
  125.         }
  126.     }
  127.  
  128.     realcount = count;
  129.     if (count < 10)
  130.         count = 10;    // allways make a visible effect
  131.  
  132.     // play an apropriate pain sound
  133.     if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
  134.     {
  135.         r = 1 + (rand()&1);
  136.         player->pain_debounce_time = level.time + 0.7;
  137.         if (player->health < 25)
  138.             l = 25;
  139.         else if (player->health < 50)
  140.             l = 50;
  141.         else if (player->health < 75)
  142.             l = 75;
  143.         else
  144.             l = 100;
  145.         gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
  146.     }
  147.  
  148.     // the total alpha of the blend is allways proportional to count
  149.     if (client->damage_alpha < 0)
  150.         client->damage_alpha = 0;
  151.     client->damage_alpha += count*0.01;
  152.     if (client->damage_alpha < 0.2)
  153.         client->damage_alpha = 0.2;
  154.     if (client->damage_alpha > 0.6)
  155.         client->damage_alpha = 0.6;        // don't go too saturated
  156.  
  157.     // the color of the blend will vary based on how much was absorbed
  158.     // by different armors
  159.     VectorClear (v);
  160.     if (client->damage_parmor)
  161.         VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
  162.     if (client->damage_armor)
  163.         VectorMA (v, (float)client->damage_armor/realcount,  acolor, v);
  164.     if (client->damage_blood)
  165.         VectorMA (v, (float)client->damage_blood/realcount,  bcolor, v);
  166.     VectorCopy (v, client->damage_blend);
  167.  
  168.  
  169.     //
  170.     // calculate view angle kicks
  171.     //
  172.     kick = abs(client->damage_knockback);
  173.     if (kick && player->health > 0)    // kick of 0 means no view adjust at all
  174.     {
  175.         kick = kick * 100 / player->health;
  176.  
  177.         if (kick < count*0.5)
  178.             kick = count*0.5;
  179.         if (kick > 50)
  180.             kick = 50;
  181.  
  182.         VectorSubtract (client->damage_from, player->s.origin, v);
  183.         VectorNormalize (v);
  184.         
  185.         side = DotProduct (v, right);
  186.         client->v_dmg_roll = kick*side*0.3;
  187.         
  188.         side = -DotProduct (v, forward);
  189.         client->v_dmg_pitch = kick*side*0.3;
  190.  
  191.         client->v_dmg_time = level.time + DAMAGE_TIME;
  192.     }
  193.  
  194.     //
  195.     // clear totals
  196.     //
  197.     client->damage_blood = 0;
  198.     client->damage_armor = 0;
  199.     client->damage_parmor = 0;
  200.     client->damage_knockback = 0;
  201. }
  202.  
  203.  
  204.  
  205.  
  206. /*
  207. ===============
  208. SV_CalcViewOffset
  209.  
  210. Auto pitching on slopes?
  211.  
  212.   fall from 128: 400 = 160000
  213.   fall from 256: 580 = 336400
  214.   fall from 384: 720 = 518400
  215.   fall from 512: 800 = 640000
  216.   fall from 640: 960 = 
  217.  
  218.   damage = deltavelocity*deltavelocity  * 0.0001
  219.  
  220. ===============
  221. */
  222. void SV_CalcViewOffset (edict_t *ent)
  223. {
  224.     float        *angles;
  225.     float        bob;
  226.     float        ratio;
  227.     float        delta;
  228.     vec3_t        v;
  229.  
  230.  
  231. //===================================
  232.  
  233.     // base angles
  234.     angles = ent->client->ps.kick_angles;
  235.  
  236.     // if dead, fix the angle and don't add any kick
  237.     if (ent->deadflag)
  238.     {
  239.         VectorClear (angles);
  240.  
  241.         ent->client->ps.viewangles[ROLL] = 40;
  242.         ent->client->ps.viewangles[PITCH] = -15;
  243.         ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
  244.     }
  245.     else
  246.     {
  247.         // add angles based on weapon kick
  248.  
  249.         VectorCopy (ent->client->kick_angles, angles);
  250.  
  251.         // add angles based on damage kick
  252.  
  253.         ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
  254.         if (ratio < 0)
  255.         {
  256.             ratio = 0;
  257.             ent->client->v_dmg_pitch = 0;
  258.             ent->client->v_dmg_roll = 0;
  259.         }
  260.         angles[PITCH] += ratio * ent->client->v_dmg_pitch;
  261.         angles[ROLL] += ratio * ent->client->v_dmg_roll;
  262.  
  263.         // add pitch based on fall kick
  264.  
  265.         ratio = (ent->client->fall_time - level.time) / FALL_TIME;
  266.         if (ratio < 0)
  267.             ratio = 0;
  268.         angles[PITCH] += ratio * ent->client->fall_value;
  269.  
  270.         // add angles based on velocity
  271.  
  272.         delta = DotProduct (ent->velocity, forward);
  273.         angles[PITCH] += delta*run_pitch->value;
  274.         
  275.         delta = DotProduct (ent->velocity, right);
  276.         angles[ROLL] += delta*run_roll->value;
  277.  
  278.         // add angles based on bob
  279.  
  280.         delta = bobfracsin * bob_pitch->value * xyspeed;
  281.         if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  282.             delta *= 6;        // crouching
  283.         angles[PITCH] += delta;
  284.         delta = bobfracsin * bob_roll->value * xyspeed;
  285.         if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  286.             delta *= 6;        // crouching
  287.         if (bobcycle & 1)
  288.             delta = -delta;
  289.         angles[ROLL] += delta;
  290.     }
  291.  
  292. //===================================
  293.  
  294.     // base origin
  295.  
  296.     VectorClear (v);
  297.  
  298.     // add view height
  299.  
  300.     v[2] += ent->viewheight;
  301.  
  302.     // add fall height
  303.  
  304.     ratio = (ent->client->fall_time - level.time) / FALL_TIME;
  305.     if (ratio < 0)
  306.         ratio = 0;
  307.     v[2] -= ratio * ent->client->fall_value * 0.4;
  308.  
  309.     // add bob height
  310.  
  311.     bob = bobfracsin * xyspeed * bob_up->value;
  312.     if (bob > 6)
  313.         bob = 6;
  314.     //gi.DebugGraph (bob *2, 255);
  315.     v[2] += bob;
  316.  
  317.     // add kick offset
  318.  
  319.     VectorAdd (v, ent->client->kick_origin, v);
  320.  
  321.     // absolutely bound offsets
  322.     // so the view can never be outside the player box
  323.  
  324.     if (v[0] < -14)
  325.         v[0] = -14;
  326.     else if (v[0] > 14)
  327.         v[0] = 14;
  328.     if (v[1] < -14)
  329.         v[1] = -14;
  330.     else if (v[1] > 14)
  331.         v[1] = 14;
  332.     if (v[2] < -22)
  333.         v[2] = -22;
  334.     else if (v[2] > 30)
  335.         v[2] = 30;
  336.  
  337.     VectorCopy (v, ent->client->ps.viewoffset);
  338. }
  339.  
  340. /*
  341. ==============
  342. SV_CalcGunOffset
  343. ==============
  344. */
  345. void SV_CalcGunOffset (edict_t *ent)
  346. {
  347.     int        i;
  348.     float    delta;
  349.  
  350.     // gun angles from bobbing
  351.     ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
  352.     ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
  353.     if (bobcycle & 1)
  354.     {
  355.         ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
  356.         ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
  357.     }
  358.  
  359.     ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
  360.  
  361.     // gun angles from delta movement
  362.     for (i=0 ; i<3 ; i++)
  363.     {
  364.         delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
  365.         if (delta > 180)
  366.             delta -= 360;
  367.         if (delta < -180)
  368.             delta += 360;
  369.         if (delta > 45)
  370.             delta = 45;
  371.         if (delta < -45)
  372.             delta = -45;
  373.         if (i == YAW)
  374.             ent->client->ps.gunangles[ROLL] += 0.1*delta;
  375.         ent->client->ps.gunangles[i] += 0.2 * delta;
  376.     }
  377.  
  378.     // gun height
  379.     VectorClear (ent->client->ps.gunoffset);
  380. //    ent->ps->gunorigin[2] += bob;
  381.  
  382.     // gun_x / gun_y / gun_z are development tools
  383.     for (i=0 ; i<3 ; i++)
  384.     {
  385.         ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
  386.         ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
  387.         ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
  388.     }
  389. }
  390.  
  391.  
  392. /*
  393. =============
  394. SV_AddBlend
  395. =============
  396. */
  397. void SV_AddBlend (float r, float g, float b, float a, float *v_blend)
  398. {
  399.     float    a2, a3;
  400.  
  401.     if (a <= 0)
  402.         return;
  403.     a2 = v_blend[3] + (1-v_blend[3])*a;    // new total alpha
  404.     a3 = v_blend[3]/a2;        // fraction of color from old
  405.  
  406.     v_blend[0] = v_blend[0]*a3 + r*(1-a3);
  407.     v_blend[1] = v_blend[1]*a3 + g*(1-a3);
  408.     v_blend[2] = v_blend[2]*a3 + b*(1-a3);
  409.     v_blend[3] = a2;
  410. }
  411.  
  412.  
  413. /*
  414. =============
  415. SV_CalcBlend
  416. =============
  417. */
  418. void SV_CalcBlend (edict_t *ent)
  419. {
  420.     int        contents;
  421.     vec3_t    vieworg;
  422.     int        remaining;
  423.  
  424.     ent->client->ps.blend[0] = ent->client->ps.blend[1] = 
  425.         ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0;
  426.  
  427.     // add for contents
  428.     VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg);
  429.     contents = gi.pointcontents (vieworg);
  430.     if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
  431.         ent->client->ps.rdflags |= RDF_UNDERWATER;
  432.     else
  433.         ent->client->ps.rdflags &= ~RDF_UNDERWATER;
  434.  
  435.     if (contents & (CONTENTS_SOLID|CONTENTS_LAVA))
  436.         SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend);
  437.     else if (contents & CONTENTS_SLIME)
  438.         SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend);
  439.     else if (contents & CONTENTS_WATER)
  440.         SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend);
  441.  
  442.     // add for powerups
  443.     if (ent->client->quad_framenum > level.framenum)
  444.     {
  445.         remaining = ent->client->quad_framenum - level.framenum;
  446.         if (remaining == 30)    // beginning to fade
  447.             gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
  448.         if (remaining > 30 || (remaining & 4) )
  449.             SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
  450.     }
  451.     else if (ent->client->invincible_framenum > level.framenum)
  452.     {
  453.         remaining = ent->client->invincible_framenum - level.framenum;
  454.         if (remaining == 30)    // beginning to fade
  455.             gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
  456.         if (remaining > 30 || (remaining & 4) )
  457.             SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend);
  458.     }
  459.     else if (ent->client->enviro_framenum > level.framenum)
  460.     {
  461.         remaining = ent->client->enviro_framenum - level.framenum;
  462.         if (remaining == 30)    // beginning to fade
  463.             gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
  464.         if (remaining > 30 || (remaining & 4) )
  465.             SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend);
  466.     }
  467.     else if (ent->client->breather_framenum > level.framenum)
  468.     {
  469.         remaining = ent->client->breather_framenum - level.framenum;
  470.         if (remaining == 30)    // beginning to fade
  471.             gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
  472.         if (remaining > 30 || (remaining & 4) )
  473.             SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend);
  474.     }
  475.  
  476.     // add for damage
  477.     if (ent->client->damage_alpha > 0)
  478.         SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1]
  479.         ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend);
  480.  
  481.     if (ent->client->bonus_alpha > 0)
  482.         SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend);
  483.  
  484.     // drop the damage value
  485.     ent->client->damage_alpha -= 0.06;
  486.     if (ent->client->damage_alpha < 0)
  487.         ent->client->damage_alpha = 0;
  488.  
  489.     // drop the bonus value
  490.     ent->client->bonus_alpha -= 0.1;
  491.     if (ent->client->bonus_alpha < 0)
  492.         ent->client->bonus_alpha = 0;
  493. }
  494.  
  495.  
  496. /*
  497. =================
  498. P_FallingDamage
  499. =================
  500. */
  501. void P_FallingDamage (edict_t *ent)
  502. {
  503.     float    delta;
  504.     int        damage;
  505.     vec3_t    dir;
  506.  
  507.     if (ent->s.modelindex != 255)
  508.         return;        // not in the player model
  509.  
  510.      if (ent->movetype == MOVETYPE_NOCLIP)
  511.         return;
  512.  
  513.     if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity))
  514.     {
  515.         delta = ent->client->oldvelocity[2];
  516.     }
  517.     else
  518.     {
  519.         if (!ent->groundentity)
  520.             return;
  521.         delta = ent->velocity[2] - ent->client->oldvelocity[2];
  522.     }
  523.     delta = delta*delta * 0.0001;
  524.  
  525. //ZOID
  526.     // never take damage if just release grapple or on grapple
  527.     if (level.time - ent->client->ctf_grapplereleasetime <= FRAMETIME * 2 ||
  528.         (ent->client->ctf_grapple && 
  529.         ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY))
  530.         return;
  531. //ZOID
  532.  
  533.     // never take falling damage if completely underwater
  534.     if (ent->waterlevel == 3)
  535.         return;
  536.     if (ent->waterlevel == 2)
  537.         delta *= 0.25;
  538.     if (ent->waterlevel == 1)
  539.         delta *= 0.5;
  540.  
  541.     if (delta < 1)
  542.         return;
  543.  
  544.     if (delta < 15)
  545.     {
  546.         ent->s.event = EV_FOOTSTEP;
  547.         return;
  548.     }
  549.  
  550.     ent->client->fall_value = delta*0.5;
  551.     if (ent->client->fall_value > 40)
  552.         ent->client->fall_value = 40;
  553.     ent->client->fall_time = level.time + FALL_TIME;
  554.  
  555.     if (delta > 30)
  556.     {
  557.         if (ent->health > 0)
  558.         {
  559.             if (delta >= 55)
  560.                 ent->s.event = EV_FALLFAR;
  561.             else
  562.                 ent->s.event = EV_FALL;
  563.         }
  564.         ent->pain_debounce_time = level.time;    // no normal pain sound
  565.         damage = (delta-30)/2;
  566.         if (damage < 1)
  567.             damage = 1;
  568.         VectorSet (dir, 0, 0, 1);
  569.  
  570.         if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
  571.             T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
  572.     }
  573.     else
  574.     {
  575.         ent->s.event = EV_FALLSHORT;
  576.         return;
  577.     }
  578. }
  579.  
  580.  
  581.  
  582. /*
  583. =============
  584. P_WorldEffects
  585. =============
  586. */
  587. void P_WorldEffects (void)
  588. {
  589.     qboolean    breather;
  590.     qboolean    envirosuit;
  591.     int            waterlevel, old_waterlevel;
  592.  
  593.     if (current_player->movetype == MOVETYPE_NOCLIP)
  594.     {
  595.         current_player->air_finished = level.time + 12;    // don't need air
  596.         return;
  597.     }
  598.  
  599.     waterlevel = current_player->waterlevel;
  600.     old_waterlevel = current_client->old_waterlevel;
  601.     current_client->old_waterlevel = waterlevel;
  602.  
  603.     breather = current_client->breather_framenum > level.framenum;
  604.     envirosuit = current_client->enviro_framenum > level.framenum;
  605.  
  606.     //
  607.     // if just entered a water volume, play a sound
  608.     //
  609.     if (!old_waterlevel && waterlevel)
  610.     {
  611.         PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  612.         if (current_player->watertype & CONTENTS_LAVA)
  613.             gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
  614.         else if (current_player->watertype & CONTENTS_SLIME)
  615.             gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  616.         else if (current_player->watertype & CONTENTS_WATER)
  617.             gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  618.         current_player->flags |= FL_INWATER;
  619.  
  620.         // clear damage_debounce, so the pain sound will play immediately
  621.         current_player->damage_debounce_time = level.time - 1;
  622.     }
  623.  
  624.     //
  625.     // if just completely exited a water volume, play a sound
  626.     //
  627.     if (old_waterlevel && ! waterlevel)
  628.     {
  629.         PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  630.         gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
  631.         current_player->flags &= ~FL_INWATER;
  632.     }
  633.  
  634.     //
  635.     // check for head just going under water
  636.     //
  637.     if (old_waterlevel != 3 && waterlevel == 3)
  638.     {
  639.         gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
  640.     }
  641.  
  642.     //
  643.     // check for head just coming out of water
  644.     //
  645.     if (old_waterlevel == 3 && waterlevel != 3)
  646.     {
  647.         if (current_player->air_finished < level.time)
  648.         {    // gasp for air
  649.             gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
  650.             PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  651.         }
  652.         else  if (current_player->air_finished < level.time + 11)
  653.         {    // just break surface
  654.             gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
  655.         }
  656.     }
  657.  
  658.     //
  659.     // check for drowning
  660.     //
  661.     if (waterlevel == 3)
  662.     {
  663.         // breather or envirosuit give air
  664.         if (breather || envirosuit)
  665.         {
  666.             current_player->air_finished = level.time + 10;
  667.  
  668.             if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
  669.             {
  670.                 if (!current_client->breather_sound)
  671.                     gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
  672.                 else
  673.                     gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
  674.                 current_client->breather_sound ^= 1;
  675.                 PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  676.                 //FIXME: release a bubble?
  677.             }
  678.         }
  679.  
  680.         // if out of air, start drowning
  681.         if (current_player->air_finished < level.time)
  682.         {    // drown!
  683.             if (current_player->client->next_drown_time < level.time 
  684.                 && current_player->health > 0)
  685.             {
  686.                 current_player->client->next_drown_time = level.time + 1;
  687.  
  688.                 // take more damage the longer underwater
  689.                 current_player->dmg += 2;
  690.                 if (current_player->dmg > 15)
  691.                     current_player->dmg = 15;
  692.  
  693.                 // play a gurp sound instead of a normal pain sound
  694.                 if (current_player->health <= current_player->dmg)
  695.                     gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
  696.                 else if (rand()&1)
  697.                     gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
  698.                 else
  699.                     gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
  700.  
  701.                 current_player->pain_debounce_time = level.time;
  702.  
  703.                 T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  704.             }
  705.         }
  706.     }
  707.     else
  708.     {
  709.         current_player->air_finished = level.time + 12;
  710.         current_player->dmg = 2;
  711.     }
  712.  
  713.     //
  714.     // check for sizzle damage
  715.     //
  716.     if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  717.     {
  718.         if (current_player->watertype & CONTENTS_LAVA)
  719.         {
  720.             if (current_player->health > 0
  721.                 && current_player->pain_debounce_time <= level.time
  722.                 && current_client->invincible_framenum < level.framenum)
  723.             {
  724.                 if (rand()&1)
  725.                     gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
  726.                 else
  727.                     gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
  728.                 current_player->pain_debounce_time = level.time + 1;
  729.             }
  730.  
  731.             if (envirosuit)    // take 1/3 damage with envirosuit
  732.                 T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
  733.             else
  734.                 T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
  735.         }
  736.  
  737.         if (current_player->watertype & CONTENTS_SLIME)
  738.         {
  739.             if (!envirosuit)
  740.             {    // no damage from slime with envirosuit
  741.                 T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
  742.             }
  743.         }
  744.     }
  745. }
  746.  
  747.  
  748. /*
  749. ===============
  750. G_SetClientEffects
  751. ===============
  752. */
  753. void G_SetClientEffects (edict_t *ent)
  754. {
  755.     int        pa_type;
  756.     int        remaining;
  757.  
  758.     ent->s.effects = 0;
  759.     ent->s.renderfx = 0;
  760.  
  761.     if (ent->health <= 0 || level.intermissiontime)
  762.         return;
  763.  
  764.     if (ent->powerarmor_time > level.time)
  765.     {
  766.         pa_type = PowerArmorType (ent);
  767.         if (pa_type == POWER_ARMOR_SCREEN)
  768.         {
  769.             ent->s.effects |= EF_POWERSCREEN;
  770.         }
  771.         else if (pa_type == POWER_ARMOR_SHIELD)
  772.         {
  773.             ent->s.effects |= EF_COLOR_SHELL;
  774.             ent->s.renderfx |= RF_SHELL_GREEN;
  775.         }
  776.     }
  777.  
  778. //ZOID
  779.     CTFEffects(ent);
  780. //ZOID
  781.  
  782.     if (ent->client->quad_framenum > level.framenum)
  783.     {
  784.         remaining = ent->client->quad_framenum - level.framenum;
  785.         if (remaining > 30 || (remaining & 4) )
  786. //            ent->s.effects |= EF_QUAD;
  787.             CTFSetPowerUpEffect(ent, EF_QUAD);
  788.     }
  789.  
  790.     if (ent->client->invincible_framenum > level.framenum)
  791.     {
  792.         remaining = ent->client->invincible_framenum - level.framenum;
  793.         if (remaining > 30 || (remaining & 4) )
  794. //            ent->s.effects |= EF_PENT;
  795.             CTFSetPowerUpEffect(ent, EF_PENT);
  796.     }
  797.  
  798.     // show cheaters!!!
  799.     if (ent->flags & FL_GODMODE)
  800.     {
  801.         ent->s.effects |= EF_COLOR_SHELL;
  802.         ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  803.     }
  804. }
  805.  
  806.  
  807. /*
  808. ===============
  809. G_SetClientEvent
  810. ===============
  811. */
  812. void G_SetClientEvent (edict_t *ent)
  813. {
  814.     if (ent->s.event)
  815.         return;
  816.  
  817.     if ( ent->groundentity && xyspeed > 225)
  818.     {
  819.         if ( (int)(current_client->bobtime+bobmove) != bobcycle )
  820.             ent->s.event = EV_FOOTSTEP;
  821.     }
  822. }
  823.  
  824. /*
  825. ===============
  826. G_SetClientSound
  827. ===============
  828. */
  829. void G_SetClientSound (edict_t *ent)
  830. {
  831.     char    *weap;
  832.  
  833.     if (ent->client->resp.game_helpchanged != game.helpchanged)
  834.     {
  835.         ent->client->resp.game_helpchanged = game.helpchanged;
  836.         ent->client->resp.helpchanged = 1;
  837.     }
  838.  
  839.     // help beep (no more than three times)
  840.     if (ent->client->resp.helpchanged && ent->client->resp.helpchanged <= 3 && !(level.framenum&63) )
  841.     {
  842.         ent->client->resp.helpchanged++;
  843.         gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
  844.     }
  845.  
  846.  
  847.     if (ent->client->pers.weapon)
  848.         weap = ent->client->pers.weapon->classname;
  849.     else
  850.         weap = "";
  851.  
  852.     if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  853.         ent->s.sound = snd_fry;
  854.     else if (strcmp(weap, "weapon_railgun") == 0)
  855.         ent->s.sound = gi.soundindex("weapons/rg_hum.wav");
  856.     else if (strcmp(weap, "weapon_bfg") == 0)
  857.         ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
  858.     else if (ent->client->weapon_sound)
  859.         ent->s.sound = ent->client->weapon_sound;
  860.     else
  861.         ent->s.sound = 0;
  862. }
  863.  
  864. /*
  865. ===============
  866. G_SetClientFrame
  867. ===============
  868. */
  869. void G_SetClientFrame (edict_t *ent)
  870. {
  871.     gclient_t    *client;
  872.     qboolean    duck, run;
  873.  
  874.     if (ent->s.modelindex != 255)
  875.         return;        // not in the player model
  876.  
  877.     client = ent->client;
  878.  
  879.     if (client->ps.pmove.pm_flags & PMF_DUCKED)
  880.         duck = true;
  881.     else
  882.         duck = false;
  883.     if (xyspeed)
  884.         run = true;
  885.     else
  886.         run = false;
  887.  
  888.     // check for stand/duck and stop/go transitions
  889.     if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
  890.         goto newanim;
  891.     if (run != client->anim_run && client->anim_priority == ANIM_BASIC)
  892.         goto newanim;
  893.     if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
  894.         goto newanim;
  895.  
  896.     if(client->anim_priority == ANIM_REVERSE)
  897.     {
  898.         if(ent->s.frame > client->anim_end)
  899.         {
  900.             ent->s.frame--;
  901.             return;
  902.         }
  903.     }
  904.     else if (ent->s.frame < client->anim_end)
  905.     {    // continue an animation
  906.         ent->s.frame++;
  907.         return;
  908.     }
  909.  
  910.     if (client->anim_priority == ANIM_DEATH)
  911.         return;        // stay there
  912.     if (client->anim_priority == ANIM_JUMP)
  913.     {
  914.         if (!ent->groundentity)
  915.             return;        // stay there
  916.         ent->client->anim_priority = ANIM_WAVE;
  917.         ent->s.frame = FRAME_jump3;
  918.         ent->client->anim_end = FRAME_jump6;
  919.         return;
  920.     }
  921.  
  922. newanim:
  923.     // return to either a running or standing frame
  924.     client->anim_priority = ANIM_BASIC;
  925.     client->anim_duck = duck;
  926.     client->anim_run = run;
  927.  
  928.     if (!ent->groundentity)
  929.     {
  930. //ZOID: if on grapple, don't go into jump frame, go into standing
  931. //frame
  932.         if (client->ctf_grapple) {
  933.             ent->s.frame = FRAME_stand01;
  934.             client->anim_end = FRAME_stand40;
  935.         } else {
  936. //ZOID
  937.         client->anim_priority = ANIM_JUMP;
  938.         if (ent->s.frame != FRAME_jump2)
  939.             ent->s.frame = FRAME_jump1;
  940.         client->anim_end = FRAME_jump2;
  941.     }
  942.     }
  943.     else if (run)
  944.     {    // running
  945.         if (duck)
  946.         {
  947.             ent->s.frame = FRAME_crwalk1;
  948.             client->anim_end = FRAME_crwalk6;
  949.         }
  950.         else
  951.         {
  952.             ent->s.frame = FRAME_run1;
  953.             client->anim_end = FRAME_run6;
  954.         }
  955.     }
  956.     else
  957.     {    // standing
  958.         if (duck)
  959.         {
  960.             ent->s.frame = FRAME_crstnd01;
  961.             client->anim_end = FRAME_crstnd19;
  962.         }
  963.         else
  964.         {
  965.             ent->s.frame = FRAME_stand01;
  966.             client->anim_end = FRAME_stand40;
  967.         }
  968.     }
  969. }
  970.  
  971.  
  972. /*
  973. =================
  974. ClientEndServerFrame
  975.  
  976. Called for each player at the end of the server frame
  977. and right after spawning
  978. =================
  979. */
  980. void ClientEndServerFrame (edict_t *ent)
  981. {
  982.     float    bobtime;
  983.     int        i;
  984.  
  985.     current_player = ent;
  986.     current_client = ent->client;
  987.  
  988.     //
  989.     // If the origin or velocity have changed since ClientThink(),
  990.     // update the pmove values.  This will happen when the client
  991.     // is pushed by a bmodel or kicked by an explosion.
  992.     // 
  993.     // If it wasn't updated here, the view position would lag a frame
  994.     // behind the body position when pushed -- "sinking into plats"
  995.     //
  996.     for (i=0 ; i<3 ; i++)
  997.     {
  998.         current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
  999.         current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
  1000.     }
  1001.  
  1002.     //
  1003.     // If the end of unit layout is displayed, don't give
  1004.     // the player any normal movement attributes
  1005.     //
  1006.     if (level.intermissiontime)
  1007.     {
  1008.         // FIXME: add view drifting here?
  1009.         current_client->ps.blend[3] = 0;
  1010.         current_client->ps.fov = 90;
  1011.         G_SetStats (ent);
  1012.         return;
  1013.     }
  1014.  
  1015.     AngleVectors (ent->client->v_angle, forward, right, up);
  1016.  
  1017.     // burn from lava, etc
  1018.     P_WorldEffects ();
  1019.  
  1020.     //
  1021.     // set model angles from view angles so other things in
  1022.     // the world can tell which direction you are looking
  1023.     //
  1024.     if (ent->client->v_angle[PITCH] > 180)
  1025.         ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
  1026.     else
  1027.         ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
  1028.     ent->s.angles[YAW] = ent->client->v_angle[YAW];
  1029.     ent->s.angles[ROLL] = 0;
  1030.     ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
  1031.  
  1032.     //
  1033.     // calculate speed and cycle to be used for
  1034.     // all cyclic walking effects
  1035.     //
  1036.     xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
  1037.  
  1038.     if (xyspeed < 5)
  1039.     {
  1040.         bobmove = 0;
  1041.         current_client->bobtime = 0;    // start at beginning of cycle again
  1042.     }
  1043.     else if (ent->groundentity)
  1044.     {    // so bobbing only cycles when on ground
  1045.         if (xyspeed > 210)
  1046.             bobmove = 0.25;
  1047.         else if (xyspeed > 100)
  1048.             bobmove = 0.125;
  1049.         else
  1050.             bobmove = 0.0625;
  1051.     }
  1052.     
  1053.     bobtime = (current_client->bobtime += bobmove);
  1054.  
  1055.     if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
  1056.         bobtime *= 4;
  1057.  
  1058.     bobcycle = (int)bobtime;
  1059.     bobfracsin = fabs(sin(bobtime*M_PI));
  1060.  
  1061.     // detect hitting the floor
  1062.     P_FallingDamage (ent);
  1063.  
  1064.     // apply all the damage taken this frame
  1065.     P_DamageFeedback (ent);
  1066.  
  1067.     // determine the view offsets
  1068.     SV_CalcViewOffset (ent);
  1069.  
  1070.     // determine the gun offsets
  1071.     SV_CalcGunOffset (ent);
  1072.  
  1073.     // determine the full screen color blend
  1074.     // must be after viewoffset, so eye contents can be
  1075.     // accurately determined
  1076.     // FIXME: with client prediction, the contents
  1077.     // should be determined by the client
  1078.     SV_CalcBlend (ent);
  1079.  
  1080. //ZOID
  1081.     if (!ent->client->chase_target)
  1082. //ZOID
  1083.         G_SetStats (ent);
  1084.  
  1085. //ZOID
  1086. //update chasecam follower stats
  1087.     for (i = 1; i <= maxclients->value; i++) {
  1088.         edict_t *e = g_edicts + i;
  1089.         if (!e->inuse || e->client->chase_target != ent)
  1090.             continue;
  1091.         memcpy(e->client->ps.stats, 
  1092.             ent->client->ps.stats, 
  1093.             sizeof(ent->client->ps.stats));
  1094.         e->client->ps.stats[STAT_LAYOUTS] = 1;
  1095.         break;
  1096.     }
  1097. //ZOID
  1098.  
  1099.  
  1100.     G_SetClientEvent (ent);
  1101.  
  1102.     G_SetClientEffects (ent);
  1103.  
  1104.     G_SetClientSound (ent);
  1105.  
  1106.     G_SetClientFrame (ent);
  1107.  
  1108.     VectorCopy (ent->velocity, ent->client->oldvelocity);
  1109.     VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
  1110.  
  1111.     // clear weapon kicks
  1112.     VectorClear (ent->client->kick_origin);
  1113.     VectorClear (ent->client->kick_angles);
  1114.  
  1115.     // if the scoreboard is up, update it
  1116.     if (ent->client->showscores && !(level.framenum & 31) )
  1117.     {
  1118. //ZOID
  1119.         if (ent->client->menu) {
  1120.             PMenu_Do_Update(ent);
  1121.             ent->client->menudirty = false;
  1122.             ent->client->menutime = level.time;
  1123.         } else
  1124. //ZOID
  1125.             DeathmatchScoreboardMessage (ent, ent->enemy);
  1126.         gi.unicast (ent, false);
  1127.     }
  1128. }
  1129.  
  1130.